import {
    ArgumentMetadata,
    HttpException,
    HttpStatus,
    Injectable,
    PipeTransform,
} from '@nestjs/common';
import { plainToInstance } from 'class-transformer';
import { validate } from 'class-validator';
import { SqlQueryDto, SqlWhereConditionEnum } from '../type/app.dto';
import {
    FindManyOptions,
    Between,
    Like,
    Equal,
    MoreThan,
    MoreThanOrEqual,
    In,
    LessThan,
    LessThanOrEqual,
    IsNull,
    Not,
} from 'typeorm';
import { isEmpty, omit, isNil } from 'lodash';

@Injectable()
export class SqlQueryPipe implements PipeTransform {
    async transform(value: SqlQueryDto, metadata: ArgumentMetadata) {
        // const dto = plainToInstance(metadata.metatype, value);
        const dto = plainToInstance(SqlQueryDto, value);
        const errors = await validate(dto);
        // console.log('errors', errors);
        if (errors.length) {
            throw new HttpException(
                { message: 'SqlQueryPipe参数错误' },
                HttpStatus.BAD_REQUEST,
            );
        }
        const data: FindManyOptions = {};
        // select
        if (value.select) {
            const selectObj = {};
            for (const field of value.select) {
                selectObj[field] = true;
            }
            data['select'] = selectObj;
        }

        // where
        if (value.where) {
            // typeorm where 表达式中并列条件 {}表示and []表示or
            const whereObj = {}; //当前只处理and
            for (const field in value.where) {
                if (Object.prototype.hasOwnProperty.call(value.where, field)) {
                    const item = value.where[field];
                    for (const condition in item) {
                        if (
                            Object.prototype.hasOwnProperty.call(
                                item,
                                condition,
                            )
                        ) {
                            const val = item[condition];
                            if (condition === SqlWhereConditionEnum.between) {
                                whereObj[field] = Between(val[0], val[1]);
                            }
                            if (condition === SqlWhereConditionEnum.contains) {
                                whereObj[field] = Like(`%${val}%`);
                            }
                            if (condition === SqlWhereConditionEnum.equals) {
                                if (isNil(val)) {
                                    whereObj[field] = IsNull();
                                } else {
                                    whereObj[field] = Equal(val);
                                }
                            }
                            if (condition === SqlWhereConditionEnum.gt) {
                                whereObj[field] = MoreThan(val);
                            }
                            if (condition === SqlWhereConditionEnum.gte) {
                                whereObj[field] = MoreThanOrEqual(val);
                            }
                            if (condition === SqlWhereConditionEnum.in) {
                                whereObj[field] = In(val);
                            }
                            if (condition === SqlWhereConditionEnum.lt) {
                                whereObj[field] = LessThan(val);
                            }
                            if (condition === SqlWhereConditionEnum.lte) {
                                whereObj[field] = LessThanOrEqual(val);
                            }
                            if (condition === SqlWhereConditionEnum.not) {
                                if (isNil(val)) {
                                    whereObj[field] = Not(IsNull());
                                } else {
                                    whereObj[field] = Not(Equal(val));
                                }
                            }
                            if (condition === SqlWhereConditionEnum.notIn) {
                                whereObj[field] = Not(In(val));
                            }
                        }
                    }
                }
            }
            data['where'] = whereObj;
        }
        
        Object.assign(data, omit(value, ['select', 'where']));
        // console.log('data', data);
        // return value;
        return data;
    }
}
